/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package orchestrarehearsal;

import ilog.concert.IloException;
import ilog.concert.IloLinearIntExpr;
import ilog.concert.cppimpl.IloAllDiff;
import ilog.concert.cppimpl.IloBoolVar;
import ilog.concert.cppimpl.IloIntVar;
import ilog.concert.cppimpl.IloIntVarArray;
import ilog.concert.cppimpl.IloObjective;
import ilog.cp.cppimpl.IloCP;



/**
 *
 * @author Guillaume
 */
public class LinearModelCP extends Model{
    IloCP cplex;
    
    IloIntVarArray x;  //x[i] = piece played at time i
    IloBoolVar[][] a; //a[i][t]=1 if player i stay at time t
    IloBoolVar[][] mav; //mav[i][t]=1 if player i have played before time t
    IloBoolVar[][] map; //map[i][t]=0 if player i have to play after time t
    IloBoolVar[][] me; //me[i][t]=1 if player is playing at time t
    IloBoolVar[][] z;
    IloBoolVar[][] y;
    IloIntVar[][] ema;
    IloIntVar[][] emi;
    IloBoolVar[][] e;
    IloBoolVar[][] eb;
    
    public LinearModelCP(IloCP cplex){
        this.cplex=cplex;
    }
    
    @Override
    public void createModel(IloCP cplex, Data dat) throws IloException {
        
        //Decision variables
        a = new IloBoolVar[dat.getNbPlayers()][dat.getNbPieces()];
        mav = new IloBoolVar[dat.getNbPlayers()][dat.getNbPieces()];
        map = new IloBoolVar[dat.getNbPlayers()][dat.getNbPieces()];
        me = new IloBoolVar[dat.getNbPlayers()][dat.getNbPieces()];
        z = new IloBoolVar[dat.getNbPlayers()][dat.getNbPieces()];
        y = new IloBoolVar[dat.getNbPlayers()][dat.getNbPieces()];
        ema = new IloIntVar[dat.getNbPieces()][dat.getNbPieces()];
        emi= new IloIntVar[dat.getNbPieces()][dat.getNbPieces()];
        e = new IloBoolVar[dat.getNbPieces()][dat.getNbPieces()];
        eb = new IloBoolVar[dat.getNbPieces()][dat.getNbPieces()];
        
        //Variables' initialization
        x = new IloIntVarArray(cplex.getEnv(),dat.getNbPieces(), 0, dat.getNbPieces()-1);
//        for (int i = 0; i < dat.getNbPieces(); i++) {
//            x.add(cplex.intVar(0, dat.getNbPieces()-1));
//        }
        
        
        for (int i = 0; i < dat.getNbPlayers(); i++) {
            for (int j = 0; j < dat.getNbPieces(); j++) {
                a[i][j] = new IloBoolVar(cplex.getEnv());
                mav[i][j] = new IloBoolVar(cplex.getEnv());
                map[i][j] = new IloBoolVar(cplex.getEnv());
                me[i][j] = new IloBoolVar(cplex.getEnv());
                y[i][j] = new IloBoolVar(cplex.getEnv());
                z[i][j] = new IloBoolVar(cplex.getEnv());
            }
        }
        
        for (int i = 0; i < dat.getNbPieces(); i++) {
            for (int j = 0; j < dat.getNbPieces(); j++) {
                ema[i][j]= cplex.intVar(0, dat.getNbPieces()-1);
                emi[i][j]= cplex.intVar(0, dat.getNbPieces()-1);
                e[i][j] = new IloBoolVar(cplex.getEnv());
                eb[i][j] = new IloBoolVar(cplex.getEnv());
            }
        }
        
        
        
        //add Objective
        IloLinearIntExpr objFonc = cplex.linearIntExpr();
        for (int i = 0; i < dat.getNbPlayers(); i++) {
            for (int j = 0; j < dat.getNbPieces(); j++) {
                objFonc.addTerm(dat.getD()[i], a[i][j]);
            }
        }
        IloObjective obj = cplex.minimize(objFonc);
        cplex.add(obj);
        
        
        
        //add constraints
        IloAllDiff allDiff = new IloAllDiff(cplex.getEnv(), x); //C1
        
        for (int i = 0; i < dat.getNbPlayers(); i++) {
            for (int t = 0; t < dat.getNbPieces(); t++) {
                cplex.addGe(a[i][t], cplex.diff(y[i][t],z[i][t])); //C2
                
                IloLinearIntExpr expr = cplex.linearIntExpr();
                for (int p = 0; p < dat.getNbPieces(); p++) {
                    expr.addTerm(dat.getW()[i][p], e[p][t]);
                }
                
                cplex.addLe(y[i][t], cplex.diff(1, expr));  //C3
                cplex.addLe(y[i][t], mav[i][t]);    //C4
                cplex.addGe(y[i][t],cplex.diff(cplex.sum(
                                                cplex.diff(1, expr),mav[i][t]
                                                        ), 1)); //C5
                cplex.addLe(z[i][t], cplex.diff(1, expr));  //C6
                
                cplex.addLe(z[i][t], map[i][t]);    //C7
                cplex.addGe(z[i][t],cplex.diff(cplex.sum(
                                                cplex.diff(1, expr),map[i][t]
                                                        ), 1)); //C8
                
                cplex.addLe(a[i][t], cplex.diff(1, map[i][t]));  //C9
                
                cplex.addLe(a[i][t], mav[i][t]);    //C10
            }
        }
        
        for (int i = 0; i < dat.getNbPieces(); i++) {
            for (int t = 0; t < dat.getNbPieces(); t++) {
                //Sur le groupe de contraintes suivantes, il est peut etre nécessaire de modifier la fonction objectif (cf feuille explications)
                cplex.addGe(ema[i][t], i);  //C18
                cplex.addGe(ema[i][t], x.getIntVar(t)); //C19
                cplex.addLe(emi[i][t], i);  //C20
                cplex.addLe(emi[i][t], x.getIntVar(t)); //C21
                
                cplex.addLe(eb[i][t], 1);    //C22
                cplex.addLe(eb[i][t], cplex.diff(ema[i][t], emi[i][t])); //C23
                cplex.addGe(e[i][t], cplex.diff(1,
                                            cplex.diff(ema[i][t], emi[i][t])
                                                )); //C24
                
                cplex.addLe(e[i][t], cplex.diff(1, eb[i][t]));  //C25
            }
        }
        
        for (int i = 0; i < dat.getNbPlayers(); i++) {
            for (int t = 1; t < dat.getNbPieces(); t++) {
                IloLinearIntExpr expr13 = cplex.linearIntExpr();
                IloLinearIntExpr expr16 = cplex.linearIntExpr();
                
                for (int tp = 0; tp < t; tp++) {
                    IloLinearIntExpr expr11 = cplex.linearIntExpr();
                    for (int j = 0; j < dat.getNbPieces(); j++) {
                        expr11.addTerm(dat.getW()[i][j], e[j][tp]);
                    }
                    cplex.addGe(mav[i][t], expr11);   //C11
                    expr13.add(expr11);
                }
                cplex.addLe(mav[i][t], expr13);  //C13
                
                for (int tp = t+1; tp < dat.getNbPieces()-1; tp++) {
                    IloLinearIntExpr expr14 = cplex.linearIntExpr();
                    for (int j = 0; j < dat.getNbPieces(); j++) {
                        expr14.addTerm(dat.getW()[i][j], e[j][tp]);
                    }
                    cplex.addGe(mav[i][t], cplex.diff(1, expr14));   //C14
                    expr16.add(expr14);
                }
                cplex.addGe(mav[i][t], cplex.diff(1, expr16));  //C16
            }
            cplex.addEq(mav[i][0], 0);  //C12
            cplex.addEq(map[i][8], 0);  //C15
            
            cplex.
        }
    }

    public IloIntVarArray getX() {
        return x;
    }
    
    public void affiche(){
        for (int i = 0; i < x.getSize(); i++) {
            System.out.println(this.cplex.getValue(x.getIntVar(i)));
        }
    }
    
}
